#include "drawable.h"

Drawable::Drawable()
	: texture {nullptr}, vec22 {(SDL_Rect) {0, 0, 0, 0}, (SDL_Rect) {0, 0, 0, 0}}
{}

Drawable::Drawable(SDL_Texture *texture, bool moves)
	: Drawable()
{
	this->texture = texture;
	this->moves = moves;
}

Drawable::Drawable(SDL_Texture *texture, bool moves, Sprite sprite)
	: Drawable(texture, moves)
{
	this->register_sprite(sprite);
}

void Drawable::update(State& state, bool pressed_keys[], int& camera_x, int& camera_y)
{
	if (!this->moves)
		return;

	if (this->vec22[POS].x - camera_x >= state.window_w + 10 ||
		this->vec22[POS].x - camera_x + this->vec22[POS].w < -10 ||
		this->vec22[POS].y - camera_y >= state.window_h + 10 ||
		this->vec22[POS].y - camera_y + this->vec22[POS].h < -10) {
		this->on_screen = false;
		return;
	}

	this->vec22[DST].x = this->vec22[POS].x - camera_x;
	this->vec22[DST].y = this->vec22[POS].y - camera_y;
	this->on_screen = true;
}

void Drawable::render(SDL_Renderer *renderer)
{
	if (on_screen)
		render(renderer, texture);
}

void Drawable::render(SDL_Renderer *renderer, SDL_Texture *atlas)
{
	if (atlas == nullptr)
		return;

	if (sprites[selected_sprite].animated) {
		sprites[selected_sprite].src.x = sprites[selected_sprite].animation_x_offset + sprites[selected_sprite].src.w * (sprites[selected_sprite].current_frame / sprites[selected_sprite].duration);
		sprites[selected_sprite].current_frame = (sprites[selected_sprite].current_frame + 1) % (sprites[selected_sprite].frames * sprites[selected_sprite].duration);
	}

	SDL_RenderCopy(renderer, atlas, &sprites[selected_sprite].src, &vec22[DST]);
}

void Drawable::register_sprite(Sprite sprite)
{
	this->sprites.push_back(sprite);
}

Drawable& Drawable::set(Vec22 target, SDL_Rect r)
{
	return this->set(target, r.x, r.y, r.w, r.h);
}

Drawable& Drawable::set(Vec22 target, int x, int y, int w, int h)
{
	this->vec22[target].x = x;
	this->vec22[target].y = y;
	this->vec22[target].w = w;
	this->vec22[target].h = h;
	return *this;
}

Drawable& Drawable::set(Vec22 target, Vec22 source)
{
	this->vec22[target].x = this->vec22[source].x;
	this->vec22[target].y = this->vec22[source].y;
	this->vec22[target].w = this->vec22[source].w;
	this->vec22[target].h = this->vec22[source].h;
	return *this;
}

Drawable& Drawable::move(Vec22 target, int x, int y)
{
	this->vec22[target].x = x;
	this->vec22[target].y = y;
	return *this;
}

Drawable& Drawable::move(Vec22 target, Vec22 source)
{
	this->vec22[target].x = this->vec22[source].x;
	this->vec22[target].y = this->vec22[source].y;
	return *this;
}

Drawable& Drawable::move_inverted(Vec22 target, int window_w, int window_h, int x, int y)
{
	this->vec22[target].x = window_w - x - vec22[target].w;
	this->vec22[target].y = window_h - y - vec22[target].h;
	return *this;
}

Drawable& Drawable::center_x(Vec22 target, int total_w)
{
	this->vec22[target].x = total_w / 2 - this->vec22[target].w / 2;
	return *this;
}

Drawable& Drawable::center_y(Vec22 target, int total_h)
{
	this->vec22[target].y = total_h / 2 - this->vec22[target].h / 2;
	return *this;
}

Drawable& Drawable::center(Vec22 target, int total_w, int total_h)
{
	return this->center_x(target, total_w).center_y(target, total_h);
}

Drawable& Drawable::right_to(Vec22 target, Drawable& other, int border)
{
	this->vec22[target].x = other.vec22[target].x + other.vec22[target].w + border;
	this->vec22[target].y = other.vec22[target].y + other.vec22[target].h / 2 - this->vec22[target].h / 2;
	return *this;
}

Drawable& Drawable::below_of(Vec22 target, Drawable& other, int border)
{
	this->vec22[target].x = other.vec22[target].x;
	this->vec22[target].y = other.vec22[target].y + other.vec22[target].h + border;
	return *this;
}

Drawable& Drawable::add_x(Vec22 target, int x)
{
	this->vec22[target].x += x;
	return *this;
}

Drawable& Drawable::add_y(Vec22 target, int y)
{
	this->vec22[target].y += y;
	return *this;
}

Drawable& Drawable::add(Vec22 target, int x, int y)
{
	this->vec22[target].x += x;
	this->vec22[target].y += y;
	return *this;
}

Drawable& Drawable::scale_to_texture()
{
	if (this->texture != nullptr) {
		int w, h;
		SDL_QueryTexture(this->texture, nullptr, nullptr, &w, &h);
		vec22[DST].w = vec22[POS].w = w;
		vec22[DST].h = vec22[POS].h = h;
	}

	return *this;
}

Drawable& Drawable::scale(Vec22 target, int w, int h)
{
	this->vec22[target].w = w;
	this->vec22[target].h = h;
	return *this;
}

Drawable& Drawable::scale(Vec22 target, float f)
{
	this->vec22[target].w *= f;
	this->vec22[target].h *= f;
	return *this;
}

Drawable& Drawable::scale(Vec22 target, Vec22 source)
{
	this->vec22[target].w = this->vec22[source].w;
	this->vec22[target].h = this->vec22[source].h;
	return *this;
}